#![allow(non_snake_case)]
use leptos::{html, prelude::*};
use shq_common::prelude::Size;
use std::{fmt::{Debug, Display}, hash::Hash};
use thaw_utils::{ArcOneCallback, BoxOneCallback, ComponentRef, Model, class_list};

use crate::{InputPrefix, InputRef, InputSuffix, SelectOption, ValidType, select::select_raw::SelectRaw};
use icondata as i;
use leptos_icons::*;

#[component]
pub fn MultiSelect<T>(
    #[prop(optional, into)] values: Model<Vec<T>>,
    #[prop(optional, into)] options: MaybeProp<Vec<SelectOption<T>>>,
    #[prop(optional, into)] on_change: Option<BoxOneCallback<Vec<T>>>,
    #[prop(optional, into)] placeholder: MaybeProp<String>,
    #[prop(optional, into)] valid_type: MaybeProp<ValidType>,
    #[prop(default=true.into(), into)] border: MaybeProp<bool>,
    #[prop(optional, into)] size: MaybeProp<Size>,
    #[prop(optional)] input_prefix: Option<InputPrefix>,
    #[prop(optional)] input_suffix: Option<InputSuffix>,
    #[prop(optional, into)] disabled: MaybeProp<bool>,
    #[prop(optional, into)] can_filter: MaybeProp<bool>,
    #[prop(optional)] comp_ref: ComponentRef<InputRef>,
    #[prop(optional)] inner_max_width: u32,
    #[prop(optional)] is_init_focus: bool,
) -> impl IntoView
where
    T: Eq + Debug + Hash + Clone + Ord + Display + Sync + Send + 'static,
{
    let is_show_menu: RwSignal<bool> = RwSignal::new(false);
    let store_options = StoredValue::new(options.get());
    let select_options = Memo::new(move |_| {
        let mut labels: Vec<SelectOption<T>> = Vec::new();
        values.with(|vals| {
            for val in vals.iter() {
                store_options.with_value(|opts| {
                    if let Some(opts)=opts.as_ref(){
                        for opt in opts.iter() {
                            if opt.value == *val {
                                labels.push(opt.clone());
                            }
                        }
                    }
                });
            }
        });
        labels
    });
    let set_value = move |val: Option<T>| {
        if val.is_none() {
            values.set(vec![]);
            return;
        }
        let val = val.unwrap();
        let exists = values.with(|vs| vs.contains(&val));
        if exists {
            values.update(|vs| vs.retain(|v| v != &val));
        } else {
            values.update(|vs| vs.push(val));
        }
    };
    let on_select = ArcOneCallback::new(move |val: Option<T>| {
        set_value(val);
        if let Some(on_change) = on_change.as_ref() {
            on_change(values.get());
        }
    });
    let on_select2 = on_select.clone();
    let label_view = move || {
        select_options.with(|opts|{
            opts.iter().map(|opt|{
                let label = opt.label.clone();
                let val=opt.value.clone();
                let on_select2 = on_select2.clone();
                view!{
                    <div class="badge badge-info gap-1">
                        <span class="max-w-14 truncate">{label}</span>
                        <Icon icon=i::FiDelete on:click=move|e|{
                            e.stop_propagation();
                            on_select2(Some(val.clone()));
                        }/>
                    </div>
                }
            }).collect_view()
        })
    };
    let label_class = move || {
        if border.get().unwrap_or_default() {
            let class = valid_type.get().unwrap_or_default().as_color_str();
            format!("input input-bordered input-{}", class)
        } else {
            "".to_owned()
        }
    };
    let input_ref = NodeRef::<html::Input>::new();
    input_ref.on_load(move |_| {
        comp_ref.load(InputRef::new(input_ref));
    });
    Effect::new(
        move || {
            if let Some(input_el) = input_ref.get_untracked() {
                if is_init_focus {
                    _ = input_el.focus();
                }
            }
        }
    );
    let style_width = if inner_max_width > 0 {
        format!("max-width:{}px", inner_max_width)
    } else {
        "".to_owned()
    };
    view! {
        <SelectRaw
            values=values
            options=options.get()
            can_filter on_select
            is_show_menu
        >
            <label
                class=class_list!["flex items-center gap-1 w-full min-w-20 max-w-xs",label_class,move||size.get().unwrap_or_default().to_class("input")]
            >
                {if let Some(sp) = input_prefix.and_then(|p| p.if_.then_some(p)) {
                    Some((sp.children)())
                } else {
                    None
                }}
                <div class="flex gap-1 w-full overflow-x-auto scrollbar-h-2" style=style_width>
                    {label_view}
                </div>
                <Icon icon=i::AiCaretDownOutlined/>
                {if let Some(sp) = input_suffix.and_then(|s|s.if_.then_some(s)) {
                    Some((sp.children)())
                } else {
                    None
                }}
            </label>
        </SelectRaw>
    }
}
